perf(extension): lazy-extract bundled npm — Windows install ~30s, not 2-3min (v0.1.3)#142
Merged
Merged
Conversation
… 30s, not 2-3min) User reported v0.1.2 takes 2-3 minutes to install via "Install from VSIX..." on Windows — much slower than previous builds. Root cause is the .vscodeignore fix in PR #141 that started shipping the bundled node_modules/npm/ tree (~3000 small .js files) instead of silently filtering it. The .vsix size stayed the same (~32 MB, npm compresses well), but Cursor's installer creates each file via CreateFileW which on Windows triggers filter drivers (Windows Defender scan, OneDrive sync, third-party AV) per file. 3000 files × ~50 ms per filter-driver round-trip = ~2.5 min install. Fix: ship the bundled runtime in TWO pieces inside the .vsix: - extension/bin/node-runtime/node.exe (expanded, ~72 MB) - extension/bin/node-runtime/npm-bundle.tar.gz (compressed, ~10 MB) Cursor's installer now writes just two large files at install time. The tarball gets extracted lazily on the user's machine when they first enable search mode — via Windows' built-in tar.exe (bundled since Win10 1803 / 2018, present on every supported Cursor target). Trade-off: - Install time: ~2-3 min → ~30 s (huge win for every install/update) - First search-mode-enable: +5-10 s for one-time tar extraction - Users who never enable search mode pay zero cost - Disk after extract: same as before (tarball + expanded files coexist, ~10 MB tarball overhead until reinstall) Files: - .github/workflows/publish-extension.yml — replace `cp -r node-v.../. extension/bin/node-runtime/` with two steps: cp node.exe, then `tar -czf` everything else into npm-bundle.tar.gz. Verify-step REQUIRED list now checks for the tarball instead of npm-cli.js. - extension/src/bundled-runtime.ts (NEW) — ensureBundledNpmExtracted() helper. Idempotent (skip if npm-cli.js already exists). Uses Windows tar.exe via execFileSync. setExtensionPath() module-level cache mirrors the spawn-binary.ts setBundledNode pattern. - extension/src/extension.ts — call setBundledRuntimePath at activation alongside setBundledNode. - extension/src/search-mode.ts — call ensureBundledNpmExtracted() before spawning the binary that runs npm install. Surface extraction errors as a clear toast with "Show output" affordance. - extension/package.json — bump 0.1.2 → 0.1.3. POSIX path unchanged — bundled-runtime.ts is a no-op there since Linux/macOS execute the shebang shim natively without bundled Node. Will VM-validate before flagging green to user. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Belt-and-braces companion to extension/src/bundled-runtime.ts. The extension extracts npm-bundle.tar.gz at user opt-in time (clicking "Enable semantic search" in the sidebar). But CORE search-install.ts is also invoked from contexts where the extension's pre-extract step doesn't run — e.g. a user shelling out `axme-code config set context.mode search` directly from a terminal, or any tooling that invokes the bundled binary without going through the extension UI. Now CORE's resolveNpm() probes for the canonical sentinel (node_modules/npm/bin/npm-cli.js). If missing AND a sibling npm-bundle.tar.gz exists, it shells out to Windows tar.exe to extract it in place. Idempotent — no-op once npm-cli.js is present, no-op on POSIX, no-op when no tarball is shipped (the user installed via curl not via .vsix, so they have system npm anyway). Failures during extraction are swallowed — resolveNpm() will then fall through to its existing npm.cmd-on-PATH fallback, which gives a useful error if neither path works. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…t for 5-10s
User reported clicking "Enable semantic search" in the sidebar showed
no UI response for ~1 minute on Windows, then suddenly the install
completed. Root cause was the lazy-extract step landing in v0.1.3:
ensureBundledNpmExtracted() ran via execFileSync (synchronous,
blocking) BEFORE vscode.window.withProgress fired. So between the
user's "Enable" click in the modal and the progress notification
appearing, 5-10 s of tar extraction blocked the extension host
event loop — sidebar froze, button looked dead, no toast, no
progress.
Two changes:
1. bundled-runtime.ts: ensureBundledNpmExtracted() is now async,
using execFile via util.promisify instead of execFileSync. Tar
extraction yields back to the event loop so sidebar / UI stay
responsive during the 5-10 s.
2. search-mode.ts: BOTH steps (extract + npm install) now run
inside the same withProgress block, each with its own
progress.report message:
"Preparing bundled Node runtime..." (the lazy extract)
"Installing semantic-search runtime + indexing..." (npm)
User sees feedback immediately after clicking Enable, instead
of a dead button for the first 5-10 s.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
v0.1.3 perf improvement: Windows .vsix install time goes from ~2-3 min back down to ~30 s by shipping the bundled npm runtime as a tarball instead of expanded files. Lazy-extract at first search-mode enable.
Reported by @geobelsky after v0.1.2: install via "Install from VSIX..." took 2-3 minutes vs the ~30 s of earlier builds. Same .vsix size though (~32 MB).
Root cause
PR #141's
.vscodeignorefix (**/node_modules/**→node_modules/**) correctly started shipping the bundledextension/bin/node-runtime/node_modules/npm/tree (~3000 small .js files). Without that,npm install @huggingface/transformerscouldn't run, search mode was broken.But on Windows, Cursor's installer extracts each .vsix file via
CreateFileW. Filter drivers (Windows Defender scan, OneDrive sync agent, third-party AV) hit every single file — ~50 ms each. 3000 small files × filter-driver round-trip = ~2.5 min of install time, even though the compressed .vsix stays small.Fix
Ship the runtime as two files inside
extension/bin/node-runtime/:node.exe(expanded, ~72 MB single file)npm-bundle.tar.gz(~10 MB compressed — npm CLI scripts +node_modules/npm/+ ancillary files)Cursor's installer writes two large files instead of thousands — bypasses the per-file filter-driver storm. The extension lazy-extracts the tarball when the user first enables search mode, via Windows' built-in
tar.exe(bundled since Win10 1803 / 2018, present on every supported Cursor target).Trade-off
POSIX path unchanged — Linux / macOS execute the shebang shim natively without bundled Node.
Files changed
.github/workflows/publish-extension.ymlcp -rof full Node tree withcp node.exe+tar -czf npm-bundle.tar.gz everything-else. Verify-step checks fornpm-bundle.tar.gzinstead of unpacked npm files.extension/src/bundled-runtime.ts(NEW)ensureBundledNpmExtracted()helper. Idempotent (sentinel =node_modules/npm/bin/npm-cli.js). Uses Windowstar.exeviaexecFileSync.setExtensionPath()module-level cache mirrorssetBundledNode()pattern.extension/src/extension.tssetBundledRuntimePath(context.extensionPath)at activation.extension/src/search-mode.tsensureBundledNpmExtracted()right before spawning the binary that runsnpm install. Surface extraction errors via toast + Show-output affordance.extension/package.json0.1.2→0.1.3.+185 / −31. Type-check + build clean.
Verification plan
VM-validation via the Azure Windows VM is planned before declaring the .vsix ready — same as for PR #141.
Out of scope
~/.local/share/axme-code/runtime, not in our .vsix🤖 Generated with Claude Code